import Watcher from "./observe/watcher";
import { createElementVNode, createTextVNode } from "./vdom";
import { patch } from "./vdom/patch";


export function instLifeCycle(Vue) {
  // 将虚拟dom转为真实dom
  Vue.prototype._update = function (vnode) {
    const vm = this;
    const el = vm.$el;
    const prevVNode = vm._vnode;
    // 把组件第一次产生的虚拟节点存一份
    vm._vnode = vnode;
    if (prevVNode) {
      vm.$el = patch(prevVNode, vnode);
    } else {
      // patch既有初始化功能,又有更新功能
      vm.$el = patch(el, vnode);
    }
  }
  // 根据render生成虚拟dom
  Vue.prototype._render = function () {
    const vm = this;
    // 当渲染时,去实例中取值,可以将视图和数据绑定在一起
    return vm.$options.render.call(vm);
  }
  // 处理标签节点
  Vue.prototype._c = function () {
    return createElementVNode(this, ...arguments);
  }
  // 处理文本节点
  Vue.prototype._v = function () {
    return createTextVNode(this, ...arguments);
  }
  // 处理模板变量{{ XXX }}
  Vue.prototype._s = function (value) {
    // 不是对象就不转成字符串了
    if (typeof value !== 'object') return value;
    // 此时value已经是真正的值了
    return JSON.stringify(value);
  }
}

// 挂载组件实例
export function mountComponent(vm, el) {
  vm.$el = el;
  // 更新视图
  const updateComponent = () => {
    // 调用render方法,产生虚拟dom
    const vnode = vm._render();
    // 根据虚拟dom产生真实dom
    vm._update(vnode);
  }
  // 回调一重新执行就会渲染页面,true代表这是个渲染watcher
  new Watcher(vm, updateComponent, true);
}

// 执行生命周期
export function callHook(vm, hook) {
  const handlers = vm.$options[hook];
  if (handlers) {
    handlers.forEach(handler => handler.call(vm));
  }
}